package com.jsyso.weixin.utils;

import java.io.IOException;
import java.io.StringReader;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.jsyso.jsyso.util.JsMap;

/**
 * XML解析工具类
 * @author janjan, xujian_jason@163.com
 *
 */
public class XML {
	private final XPath path;
    private final Document doc;
    
    public static String mapToXml(Map<String, String> params) {
        StringBuilder xml = new StringBuilder();
        xml.append("<xml>");
        for (Entry<String, String> entry : params.entrySet()) {
            String key   = entry.getKey();
            String value = entry.getValue();
            // 略过空值
            if (StringUtils.isBlank(value)) continue;
            xml.append("<").append(key).append(">");
                xml.append(entry.getValue());
            xml.append("</").append(key).append(">");
        }
        xml.append("</xml>");
        return xml.toString();
    }
    
    public static JsMap xmlToMap(String xmlStr) {
    	XML xml = XML.create(xmlStr);
    	return xml.toMap();
    }
    
    public static XML create(InputSource inputSource) {
    	try {
            return new XML(inputSource);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    public static XML create(String xmlStr) {
    	 StringReader sr = new StringReader(xmlStr.trim());
         InputSource inputSource = new InputSource(sr);
         XML xml = create(inputSource);
         IOUtils.closeQuietly(sr);
         return xml;
    }
    
    private XML(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {
    	 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(inputSource);
         path = XPathFactory.newInstance().newXPath();
	}
    
    private Object evalXPath(String expression, Object item, QName returnType) {
        item = null == item ? doc : item;
        try {
            return path.evaluate(expression, item, returnType);
        } catch (XPathExpressionException e) {
            throw new RuntimeException(e);
        }
    }
    
    public JsMap toMap() {
        Element root = doc.getDocumentElement();
        JsMap params = JsMap.create();
        // 将节点封装成map形式
        NodeList list = root.getChildNodes();
        for (int i = 0; i < list.getLength(); i++) {
            Node node = list.item(i);
            if (node instanceof Element) {
                params.put(node.getNodeName(), node.getTextContent());
            }
        }
        return params;
    }
    
    public String getString(String expression) {
        return (String) evalXPath(expression, null, XPathConstants.STRING);
    }
    
    public Number getNumber(String expression) {
        return (Number) evalXPath(expression, null, XPathConstants.NUMBER);
    }
}
